<?php
/**
 * @subpackage dao
 * @author     d-tran
 * add all addWhere  -> addWhereOr
 * Neu add lan lon luc goi den getWhere thi se bi loi cac gia tri where ko dung thu tu
 */
class Dao {
	protected $_table;
	protected $_db;
	protected $_sql = array();
	protected $_fetch_mode = NULL;
	protected $_row_effect = NULL;

	/**
	 * increasing
	 * 1, 2, 3
	 * */
	const ORDER_ASC 		= "asc";

	/**
	 * decreasing
	 * 3, 2, 1
	 */
	const ORDER_DESC 		= "desc";

	const COMP_EQUAL		= " = ";
	const COMP_LESS_THAN	= " < ";
	const COMP_LESS_EQUAL	= " <= ";
	const COMP_GREATER_THAN	= " > ";
	const COMP_GREATER_EQUAL= " >= ";
	const COMP_NOT_EQUAL	= " <> ";

	const STR_NULL			= "";
	const STR_ZERO			= "0";

	protected $cols = array();

	protected $distinct = NULL;

	protected $values = array();

	protected $where = array();
	protected $where_or = array();
	protected $where_values = array();


	public function __construct($db)
	{
		$this->_db = $db;
	}

	function select(){
		$st = $this->_db->prepare($this->buildSelectSql());
		$st->execute($this->where_values);

		//debug
		if(DEVELOPMENT) {
			$this->_sql['select']['sql'] = $this->buildSelectSql();
			$this->_sql['select']['where'] = '('. implode(', ', $this->where_values). ')';
		}
		//debug

		if($this->_fetch_mode) return $result->fetchAll($this->_fetch_mode);
		return $st->fetchAll();
	}

	function insert() {
		$st = $this->_db->prepare($this->buildInsertSql());
		$st->execute($this->values);
		// debug
		if(DEVELOPMENT) {
			$this->_sql['insert']['sql'] = $this->buildInsertSql();
			$this->_sql['insert']['where'] = $this->values;
		}
		// debug
	}

	function update() {
		$st = $this->_db->prepare($this->buildUpdateSql());
		$st->execute(array_merge($this->values, $this->where_values));

		//debug
		if(DEVELOPMENT) {
			$this->_row_effect = $st->rowCount();
			$this->_sql['update']['sql'] = $this->buildUpdateSql();
			$w = array_merge($this->values, $this->where_values);
			$this->_sql['update']['where'] = '('. implode(', ', $w) .')';
			$this->_sql['update']['_row_effect'] = $this->_row_effect;
		}
		// debug
	}

	function delete() {
		$st = $this->_db->prepare($this->buildDeleteSql());
		$st->execute($this->where_values);
		//debug
		if(DEVELOPMENT) {
			$this->_row_effect = $st->rowCount();
			$this->_sql['delete']['sql'] = $this->buildDeleteSql();
			$w = array_merge($this->where_values);
			$this->_sql['delete']['where'] = '('. implode(', ', $w) .')';
			$this->_sql['update']['_row_effect'] = $this->_row_effect;
		}
		// debug
	}

	function selectStatment($sql, $where){
		$st = $this->_db->prepare($sql);
		$st->execute($where);
		if($this->_fetch_mode) return $result->fetchAll($this->_fetch_mode);
		return $st->fetchAll();
	}

	function insertStatment($sql, $where) {
		$st = $this->_db->prepare($sql);
		$st->execute($where);
	}

	function updateStatment($sql, $where) {
		$st = $this->_db->prepare($sql);
		$st->execute($where);
	}

	function deleteStatment($sql, $where) {
		$st = $this->_db->prepare($sql);
		$st->execute($where);
	}

	public function buildSelectSql() {
		$sql = "SELECT ";

		if(count($this->cols) == 0){
			$sql .= "*";
		} else {
			$sql .= implode(', ', $this->select);
		}

		$sql .= " FROM " . $this->_table;

		$sql .= $this->getWhere();

		return $sql;
	}

	public function buildInsertSql() {
		$sql = 'INSERT INTO ' . $this->_table;

		$sql .= '(';
		$sql .= implode(', ', $this->cols);
		$sql .= ')';

		$sql .= ' VALUES ';

		$v = array_fill(0, count($this->cols), '?');
		$sql .= '(';
		$sql .= implode(',', $v);
		$sql .= ')';

		return $sql;
	}

	function buildUpdateSql() {
		$sql = 'UPDATE ' . $this->_table;
		$sql .= ' SET ';

		$set = implode('=?, ', $this->cols); // ('id', 'name', 'age') -> id=?, name=?, age
		$set .= ' =?'; // id=?, name=?, age -> id=?, name=?, age=?

		$sql .= $set;

		$sql .= $this->getWhere();

		return $sql;
	}

	function buildDeleteSql() {
		$sql = 'DELETE FROM ' . $this->_table;
		$sql .= $this->getWhere();
		return $sql;
	}

	function addSelect($col) {
		$this->cols[] = $col;
	}

	function addValue($col, $val) {
		$this->cols[] = $col;
		$this->values[] = $val;
	}

	function getWhere() {
		$where .= implode(' AND ', $this->where);
		$where_or = implode(' OR ', $this->where_or);

		if(!$this->where && !$this->where) return '';

		if(!$where_or) return ' WHERE ' . $where;
		if(!$where) return ' WHERE ' . $where_or;

		return ' WHERE ' .'('  .$where. ')' . ' OR ' . '('. $where_or .')';
	}

	function addWhere($col, $val, $compare = self::COMP_EQUAL) {
		$this->where[] = $col . $compare. '?';
		$this->where_values[] = $val;
	}

	/*
	 function addWhereStr($col, $val, $compare = self::COMP_EQUAL) {
		$this->where[] = $col . $compare . ' ?';
		$this->where_values[] = "'" . $val ."'";
		}
		*/

	function addWhereOr($col, $val, $compare=self::COMP_EQUAL) {
		$this->where_or[] = $col . $compare . ' ?';
		$this->where_values[] = $val;
	}

	/*
	 function addWhereStrOr($col, $val, $compare=self::COMP_EQUAL) {
		$this->where_or[] = $col . $compare . ' ?';
		$this->where_values[] = "'" . $val ."'";
		}
		*/

	function reset() {
		$this->select = array();
		$this->values = array();
		$this->where = array();
		$this->where_or = array();
		$this->where_values = array();
		$this->distinct = NULL;
		$this->_fetch_mode = NULL;
	}

	function setFetchMode($fetch_mode) {
		$this->_fetch_mode = $fetch_mode;
	}

	function getFetchMode() {
		return $this->_fetch_mode;
	}

	public function getSQL() {
		return $this->_sql;
	}

	public function getLastInsertId() {
		return $this->_db->lastInsertId();
	}

	public function getRowEffect() {
		return $this->_row_effect;
	}

	function setRowEffect($c) {
		$this->_row_effect = $c;
	}

}